```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RocketMQ消息重复消费与幂等性解决方案</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        :root {
            --primary: #3b82f6;
            --primary-dark: #2563eb;
            --secondary: #10b981;
            --dark: #1e293b;
            --light: #f8fafc;
        }
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #334155;
            line-height: 1.6;
            background-color: #f8fafc;
        }
        .serif {
            font-family: 'Noto Serif SC', serif;
        }
        .hero {
            background: linear-gradient(135deg, rgba(30,41,59,0.95) 0%, rgba(15,23,42,0.95) 100%), url('https://images.unsplash.com/photo-1515879218367-8466d910aaa4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2069&q=80') center/cover no-repeat;
        }
        .card {
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .code-block {
            background-color: #1e293b;
            border-left: 4px solid var(--primary);
        }
        .highlight {
            position: relative;
        }
        .highlight::before {
            content: "";
            position: absolute;
            left: -8px;
            top: 0;
            height: 100%;
            width: 4px;
            background-color: var(--primary);
            border-radius: 4px;
        }
        .mermaid {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <section class="hero text-white py-20 md:py-32 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl">
            <div class="flex flex-col items-center text-center">
                <h1 class="serif text-4xl md:text-5xl font-bold mb-6 leading-tight">
                    RocketMQ消息重复消费<br>与幂等性解决方案
                </h1>
                <p class="text-xl md:text-2xl opacity-90 mb-8 max-w-3xl">
                    深入剖析消息中间件中的重复消费问题，提供全面的幂等性实现方案
                </p>
                <div class="flex space-x-4">
                    <a href="#reasons" class="px-6 py-3 bg-blue-600 hover:bg-blue-700 rounded-lg font-medium transition-colors flex items-center">
                        <i class="fas fa-search mr-2"></i> 问题原因
                    </a>
                    <a href="#solutions" class="px-6 py-3 bg-white text-blue-600 hover:bg-gray-100 rounded-lg font-medium transition-colors flex items-center">
                        <i class="fas fa-lightbulb mr-2"></i> 解决方案
                    </a>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <div class="container mx-auto max-w-5xl px-4 py-12 md:py-16">
        <!-- Intro -->
        <section class="mb-16">
            <div class="bg-white rounded-xl p-8 shadow-lg">
                <h2 class="serif text-3xl font-bold text-gray-800 mb-4">消息重复消费问题概述</h2>
                <p class="text-gray-700 mb-6">
                    在分布式系统中，消息队列是实现异步通信和解耦的重要组件。然而，由于网络不可靠、系统故障等因素，<span class="font-semibold text-blue-600">消息重复消费</span>成为一个常见问题。RocketMQ作为一款流行的消息中间件，同样面临着这一挑战。
                </p>
                <p class="text-gray-700">
                    本文将系统性地分析导致消息重复消费的各种原因，并提供多种实现消费幂等性的解决方案，帮助开发者构建更健壮的消息处理系统。
                </p>
            </div>
        </section>

        <!-- Reasons Section -->
        <section id="reasons" class="mb-16">
            <h2 class="serif text-3xl font-bold text-gray-800 mb-8 text-center">消息重复消费的原因</h2>
            
            <div class="grid md:grid-cols-3 gap-6 mb-12">
                <!-- Producer Card -->
                <div class="card bg-white rounded-xl p-6">
                    <div class="flex items-center mb-4">
                        <div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 mr-4">
                            <i class="fas fa-paper-plane text-xl"></i>
                        </div>
                        <h3 class="serif text-xl font-bold">生产者端原因</h3>
                    </div>
                    <ul class="space-y-3 text-gray-700">
                        <li class="flex items-start">
                            <i class="fas fa-bolt text-blue-500 mt-1 mr-2"></i>
                            <span>网络闪断导致的重试</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-server text-blue-500 mt-1 mr-2"></i>
                            <span>Broker端异常响应</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-cog text-blue-500 mt-1 mr-2"></i>
                            <span>客户端配置问题</span>
                        </li>
                    </ul>
                </div>
                
                <!-- Consumer Card -->
                <div class="card bg-white rounded-xl p-6">
                    <div class="flex items-center mb-4">
                        <div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center text-green-600 mr-4">
                            <i class="fas fa-user text-xl"></i>
                        </div>
                        <h3 class="serif text-xl font-bold">消费者端原因</h3>
                    </div>
                    <ul class="space-y-3 text-gray-700">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                            <span>消费确认异常</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-sync-alt text-green-500 mt-1 mr-2"></i>
                            <span>集群模式重平衡</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-power-off text-green-500 mt-1 mr-2"></i>
                            <span>消费者异常退出</span>
                        </li>
                    </ul>
                </div>
                
                <!-- Special Mode Card -->
                <div class="card bg-white rounded-xl p-6">
                    <div class="flex items-center mb-4">
                        <div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center text-purple-600 mr-4">
                            <i class="fas fa-star text-xl"></i>
                        </div>
                        <h3 class="serif text-xl font-bold">特殊消费模式</h3>
                    </div>
                    <ul class="space-y-3 text-gray-700">
                        <li class="flex items-start">
                            <i class="fas fa-broadcast-tower text-purple-500 mt-1 mr-2"></i>
                            <span>广播消费模式</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-sort-amount-down text-purple-500 mt-1 mr-2"></i>
                            <span>顺序消费重试</span>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-redo text-purple-500 mt-1 mr-2"></i>
                            <span>消息重试机制</span>
                        </li>
                    </ul>
                </div>
            </div>

            <!-- Mermaid Diagram -->
            <div class="mermaid mb-12">
                graph TD
                    A[消息重复消费] --> B[生产者端原因]
                    A --> C[消费者端原因]
                    A --> D[特殊消费模式]
                    
                    B --> B1[网络闪断]
                    B --> B2[Broker异常]
                    B --> B3[配置问题]
                    
                    C --> C1[ACK失败]
                    C --> C2[重平衡]
                    C --> C3[异常退出]
                    
                    D --> D1[广播模式]
                    D --> D2[顺序消费]
                    D --> D3[重试队列]
            </div>
        </section>

        <!-- Solutions Section -->
        <section id="solutions" class="mb-16">
            <h2 class="serif text-3xl font-bold text-gray-800 mb-8 text-center">实现消费幂等性的方法</h2>
            
            <div class="grid md:grid-cols-2 gap-8 mb-12">
                <!-- Solution 1 -->
                <div class="card bg-white rounded-xl overflow-hidden">
                    <div class="bg-blue-600 text-white px-6 py-4">
                        <h3 class="serif text-xl font-bold flex items-center">
                            <i class="fas fa-fingerprint mr-3"></i> 业务唯一标识
                        </h3>
                    </div>
                    <div class="p-6">
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">实现方式</h4>
                        <ul class="space-y-2 text-gray-700 mb-4">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-blue-500 mt-1 mr-2"></i>
                                <span>消息设置唯一键去重</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-blue-500 mt-1 mr-2"></i>
                                <span>使用业务主键判断</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-blue-500 mt-1 mr-2"></i>
                                <span>数据库唯一索引约束</span>
                            </li>
                        </ul>
                        
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">代码示例</h4>
                        <div class="code-block rounded-lg p-4 text-gray-200 mb-4 overflow-x-auto">
                            <pre><code>// 生产者设置唯一键
Message msg = new Message("TopicTest", "TagA", 
    "Hello RocketMQ".getBytes());
msg.setKeys("ORDER_ID_12345"); // 业务唯一标识

// 消费者检查唯一键
if (isProcessed(msg.getKeys())) {
    continue; // 已处理过
}
processMessage(msg);
markAsProcessed(msg.getKeys());</code></pre>
                        </div>
                    </div>
                </div>
                
                <!-- Solution 2 -->
                <div class="card bg-white rounded-xl overflow-hidden">
                    <div class="bg-green-600 text-white px-6 py-4">
                        <h3 class="serif text-xl font-bold flex items-center">
                            <i class="fas fa-clipboard-check mr-3"></i> 状态判断机制
                        </h3>
                    </div>
                    <div class="p-6">
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">实现方式</h4>
                        <ul class="space-y-2 text-gray-700 mb-4">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>业务状态检查</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>乐观锁机制</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>状态机流转约束</span>
                            </li>
                        </ul>
                        
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">代码示例</h4>
                        <div class="code-block rounded-lg p-4 text-gray-200 mb-4 overflow-x-auto">
                            <pre><code>// 查询订单当前状态
Order order = orderService.getOrder(payment.getOrderId());

// 根据状态判断是否需要处理
if (order.getStatus() == OrderStatus.PAID) {
    continue; // 已处理过
}

// 乐观锁更新
UPDATE orders 
SET status = 'PAID', version = version + 1 
WHERE order_id = ? AND version = ?</code></pre>
                        </div>
                    </div>
                </div>
                
                <!-- Solution 3 -->
                <div class="card bg-white rounded-xl overflow-hidden">
                    <div class="bg-purple-600 text-white px-6 py-4">
                        <h3 class="serif text-xl font-bold flex items-center">
                            <i class="fas fa-lock mr-3"></i> 分布式锁与互斥
                        </h3>
                    </div>
                    <div class="p-6">
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">实现方式</h4>
                        <ul class="space-y-2 text-gray-700 mb-4">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-purple-500 mt-1 mr-2"></i>
                                <span>分布式锁实现互斥</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-purple-500 mt-1 mr-2"></i>
                                <span>Redis SETNX 命令</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-purple-500 mt-1 mr-2"></i>
                                <span>Zookeeper临时节点</span>
                            </li>
                        </ul>
                        
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">代码示例</h4>
                        <div class="code-block rounded-lg p-4 text-gray-200 mb-4 overflow-x-auto">
                            <pre><code>// 尝试获取分布式锁
boolean acquired = distributedLock.tryLock(
    "message_lock:" + messageId, 
    5, TimeUnit.SECONDS
);

if (!acquired) continue; // 其他实例正在处理

try {
    if (isProcessed(messageId)) continue;
    processMessage(msg);
    markAsProcessed(messageId);
} finally {
    distributedLock.unlock();
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <!-- Solution 4 -->
                <div class="card bg-white rounded-xl overflow-hidden">
                    <div class="bg-indigo-600 text-white px-6 py-4">
                        <h3 class="serif text-xl font-bold flex items-center">
                            <i class="fas fa-table mr-3"></i> 去重表记录
                        </h3>
                    </div>
                    <div class="p-6">
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">实现方式</h4>
                        <ul class="space-y-2 text-gray-700 mb-4">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>专用去重表记录</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>消息处理日志</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>分布式缓存记录</span>
                            </li>
                        </ul>
                        
                        <h4 class="font-semibold text-lg mb-3 text-gray-800">SQL示例</h4>
                        <div class="code-block rounded-lg p-4 text-gray-200 mb-4 overflow-x-auto">
                            <pre><code>-- 创建消息处理记录表
CREATE TABLE message_processed (
    message_id VARCHAR(64) PRIMARY KEY,
    process_time TIMESTAMP NOT NULL,
    consumer_group VARCHAR(128) NOT NULL
);

-- 插入处理记录
INSERT INTO message_processed 
VALUES(?, NOW(), ?) 
ON DUPLICATE KEY UPDATE process_time = NOW();</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Best Practices -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-lg overflow-hidden">
                <div class="bg-gradient-to-r from-blue-600 to-purple-600 text-white px-6 py-4">
                    <h2 class="serif text-2xl font-bold flex items-center">
                        <i class="fas fa-medal mr-3"></i> 实际应用中的最佳实践
                    </h2>
                </div>
                <div class="p-6">
                    <div class="grid md:grid-cols-2 gap-8">
                        <div>
                            <h3 class="serif text-xl font-bold mb-4 text-gray-800 flex items-center">
                                <i class="fas fa-sitemap text-blue-500 mr-2"></i> 多层次幂等保障
                            </h3>
                            <div class="mermaid mb-6">
                                graph LR
                                    A[消息到达] --> B[内存缓存检查]
                                    B -->|未处理| C[Redis检查]
                                    C -->|未处理| D[数据库检查]
                                    D -->|未处理| E[业务处理]
                                    E --> F[记录处理状态]
                            </div>
                            
                            <h3 class="serif text-xl font-bold mb-3 text-gray-800 flex items-center">
                                <i class="fas fa-lightbulb text-yellow-500 mr-2"></i> 设计要点
                            </h3>
                            <ul class="space-y-2 text-gray-700">
                                <li class="flex items-start">
                                    <i class="fas fa-check text-blue-500 mt-1 mr-2"></i>
                                    <span>消息键使用业务唯一标识</span>
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-check text-blue-500 mt-1 mr-2"></i>
                                    <span>幂等机制与业务解耦</span>
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-check text-blue-500 mt-1 mr-2"></i>
                                    <span>建立重复率监控告警</span>
                                </li>
                            </ul>
                        </div>
                        
                        <div>
                            <h3 class="serif text-xl font-bold mb-3 text-gray-800 flex items-center">
                                <i class="fas fa-tasks text-green-500 mr-2"></i> 场景适配策略
                            </h3>
                            <div class="space-y-4">
                                <div class="p-4 bg-blue-50 rounded-lg">
                                    <h4 class="font-semibold text-blue-700 mb-2">高频写入场景</h4>
                                    <p class="text-gray-700 text-sm">内存缓存+定期持久化，减少存储压力</p>
                                </div>
                                <div class="p-4 bg-green-50 rounded-lg">
                                    <h4 class="font-semibold text-green-700 mb-2">交易类业务</h4>
                                    <p class="text-gray-700 text-sm">业务状态+唯一索引，保证数据一致性</p>
                                </div>
                                <div class="p-4 bg-purple-50 rounded-lg">
                                    <h4 class="font-semibold text-purple-700 mb-2">日志类消息</h4>
                                    <p class="text-gray-700 text-sm">轻量级判重，可接受少量重复</p>
                                </div>
                                <div class="p-4 bg-indigo-50 rounded-lg">
                                    <h4 class="font-semibold text-indigo-700 mb-2">批量处理场景</h4>
                                    <p class="text-gray-700 text-sm">批量提交前去重，减少判断次数</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-8">
        <div class="container mx-auto max-w-5xl px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold text-white mb-2">技术小馆</h3>
                    <p class="text-sm">探索技术奥秘，分享开发心得</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="hover:text-white transition-colors flex items-center">
                        <i class="fas fa-globe mr-2"></i> http://www.yuque.com/jtostring
                    </a>
                </div>
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            fontFamily: "'Noto Sans SC', sans-serif",
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>
```